import asyncio
import random

import pygame
from pygame import K_a, K_LEFT, K_d, K_RIGHT, K_w, K_UP, K_s, K_DOWN

import cfg
from snakes.grid import Grid
from units.uiUtil import gameBgImg, playMyBgMusic, drawText

bg = pygame.image.load('snakes/myGameBg1.jpg')
snakeImg = pygame.image.load('snakes/snake.png')
getFood = pygame.mixer.Sound('snakes/getFood.mp3')

class MainSnaes:
    def __init__(self, dims, FPS=60):
        self.dims = dims
        self.FPS = FPS
        self.score = 0
        self.grids = []
        self.snakeList = []
        self.direction = "stop"
        self.count = 0
        self.frequency = 50
        self.snakeLength = 0
        self.top = 200
        self.initx, self.inity = 15, 20
        self.rat = []
        self.bgColor =  (80, 80, 80, 255)


    # 游戏主循环所在函数需要由 async 定义
    async def start(self):
        # 初始化游戏界面（screen）：尺寸、背景色等
        screen = pygame.display.set_mode(self.dims)
        # 显示游戏名称
        pygame.display.set_caption("贪吃蛇")
        # 初始化游戏时钟（clock），由于控制游戏帧率
        clock = pygame.time.Clock()
        # 播放背景音
        playMyBgMusic('assets/music/bg3.mp3')

        # 背景画网格
        self.drawGameGrid(self.dims, screen, 40)
        # 初始化蛇
        self.initSnake(screen)
        # 画贪吃蛇食物
        self.newOneFood()

        # 游戏主循环
        while cfg.inGame:
            # 按照给定的 FPS 刷新游戏
            # clock.tick() 函数返回上一次调用该函数后经历的时间，单位为毫秒 ms
            # dt 记录上一帧接受之后经历的时间，单位为秒 m
            # 使用 dt 控制物体运动可以使游戏物理过程与帧率无关
            dt = clock.tick(self.FPS) / 1000.0
            # 使用 asyncio 同步
            # 此外游戏主体代码中不需要再考虑 asyncio
            await asyncio.sleep(0)

            # 游戏事件处理
            # 包括键盘、鼠标输入等
            for event in pygame.event.get():
                # 点击关闭窗口按钮或关闭网页
                if event.type == pygame.QUIT:
                    pygame.quit()
                # 当 game_running 为 False 时，

            # 以背景色覆盖刷新游戏界面
            gameBgImg(screen, bg, 0, self.dims)

            # 画得分和速度
            drawText(f'得分：{self.snakeLength-3}', self.bgColor, (150, 100), screen)

            # 键盘事件
            key_pressed = pygame.key.get_pressed()
            if key_pressed[K_a] or key_pressed[K_LEFT]:
                if self.direction != "left" and self.direction != "right": self.direction = "left"
            elif key_pressed[K_d] or key_pressed[K_RIGHT]:
                if self.direction != "right" and self.direction != "left": self.direction = "right"
            elif key_pressed[K_w] or key_pressed[K_UP]:
                if self.direction != "up" and self.direction != "down": self.direction = "up"
            elif key_pressed[K_s] or key_pressed[K_DOWN]:
                if self.direction != "down" and self.direction != "up": self.direction = "down"

            # 移动蛇的位置
            self.count += 1
            if self.count > self.frequency:
                self.count = 0
                if self.direction == "left":
                    head = self.snakeList[self.snakeLength-1] # 头
                    sx = head[0]
                    sy = head[1] - 1 if head[1] - 1 >= 0 else self.initx-1
                    # 移动蛇
                    self.snakeMove(sx, sy)
                elif self.direction == "right":
                    head = self.snakeList[self.snakeLength - 1]  # 头
                    sx = head[0]
                    sy = head[1] + 1 if head[1] + 1 < self.initx else 0
                    # 移动蛇
                    self.snakeMove(sx, sy)
                elif self.direction == "up":
                    head = self.snakeList[self.snakeLength - 1]  # 头
                    sx = head[0] - 1 if head[0] - 1 >= 0 else self.inity-1
                    sy = head[1]
                    # 移动蛇
                    self.snakeMove(sx, sy)
                elif self.direction == "down":
                    head = self.snakeList[self.snakeLength - 1]  # 头
                    sx = head[0] + 1 if head[0] + 1 < self.inity else 0
                    sy = head[1]
                    # 移动蛇
                    self.snakeMove(sx, sy)

            for s in self.snakeList:
                # 初始化蛇
                self.grids[s[0]][s[1]].changeColor("white")
                # snake = Snake((s[0],s[1]), (40, 40), snakeImg)
                # snake.draw(screen)

            # 画蛇
            for y in range(self.inity):
                for x in range(self.initx):
                    self.grids[y][x].draw(screen)

            # 将游戏界面内容输出至屏幕
            pygame.display.update()

        # 跳出游戏主循环，退出游戏
        cfg.inGame = False

    def snakeMove(self, sx, sy):
        tail = self.snakeList[0]  # 尾
        self.snakeList.append([sx, sy])
        # 判断蛇头和食物接触就不删除蛇尾
        if self.rat[0] == sx and self.rat[1] == sy:
            self.snakeLength += 1
            getFood.play()
            self.newOneFood()
            # 速度+1
            self.frequency -= 1
        else:
            self.grids[tail[0]][tail[1]].changeColor(self.bgColor)
            self.snakeList.remove(tail)

    def newOneFood(self):
        self.rat = [random.randint(0, self.inity-1), random.randint(0, self.initx-1)]
        while self.snakeList.count(self.rat) > 0:
            self.rat = [random.randint(0, self.inity-1), random.randint(0,self.initx-1)]
        self.grids[self.rat[0]][self.rat[1]].changeColor("white")

    def initSnake(self,screen):
        self.snakeLength = 3
        self.snakeList.append([0, 0])
        self.snakeList.append([0, 1])
        self.snakeList.append([0, 2])

    def drawGameGrid(self, dims, screen, spriteSize=40):
        startx, starty = (dims[0]-spriteSize*self.initx)/2, self.top
        endx, endy = startx + self.initx*spriteSize, starty + self.inity*spriteSize

        for y in range(self.inity+1):
            pygame.draw.line(screen, (150, 150, 150), (startx, starty + y*spriteSize), (endx, starty + y*spriteSize), 1)
        for x in range(self.initx+1):
            pygame.draw.line(screen, (150, 150, 150), (startx + x*spriteSize, starty), (startx + x*spriteSize, endy), 1)

        for y in range(self.inity):
            self.grids.append([])
            for x in range(self.initx):
                grid = Grid(spriteSize,(startx+x*spriteSize, starty + y*spriteSize),self.bgColor)
                self.grids[y].append(grid)


